"""
文档扫描模块

负责扫描目录中的文件，提供文件发现和过滤功能。
"""

import os
from typing import List, Dict, Any, Optional, Generator
from pathlib import Path

from .file_types import file_type_registry, FileInfo


class DocumentScanner:
    """
    文档扫描器

    职责：
    1. 递归扫描目录中的文件
    2. 根据配置过滤文件
    3. 提供扫描统计信息
    4. 支持增量扫描
    """

    def __init__(self, data_dir: str):
        """
        初始化文档扫描器

        Args:
            data_dir: 数据目录路径
        """
        self.data_dir = data_dir
        self.file_type_registry = file_type_registry

    def validate_directory(self) -> None:
        """
        验证数据目录

        Raises:
            FileNotFoundError: 目录不存在
            NotADirectoryError: 路径不是目录
        """
        if not os.path.exists(self.data_dir):
            raise FileNotFoundError(f"数据目录不存在: {self.data_dir}")

        if not os.path.isdir(self.data_dir):
            raise NotADirectoryError(f"指定路径不是目录: {self.data_dir}")

    def scan_directory(
        self,
        recursive: bool = True,
        include_patterns: Optional[List[str]] = None,
        exclude_patterns: Optional[List[str]] = None,
        max_depth: Optional[int] = None
    ) -> List[FileInfo]:
        """
        扫描目录中的文件

        Args:
            recursive: 是否递归扫描子目录
            include_patterns: 包含的文件模式列表
            exclude_patterns: 排除的文件模式列表
            max_depth: 最大扫描深度

        Returns:
            List[FileInfo]: 扫描到的文件信息列表
        """
        self.validate_directory()

        files = []
        scanned_count = 0

        try:
            if recursive:
                files = self._scan_recursive(
                    self.data_dir,
                    include_patterns,
                    exclude_patterns,
                    max_depth,
                    0,
                    scanned_count
                )
            else:
                files = self._scan_flat(
                    self.data_dir,
                    include_patterns,
                    exclude_patterns
                )
        except KeyboardInterrupt:
            print("扫描被用户中断")
            return []

        # scanner已经返回支持的FileInfo列表，不需要额外过滤
        return files

    def _scan_flat(
        self,
        directory: str,
        include_patterns: Optional[List[str]],
        exclude_patterns: Optional[List[str]]
    ) -> List[FileInfo]:
        """平面扫描目录"""
        files = []
        try:
            for entry in os.listdir(directory):
                file_path = os.path.join(directory, entry)
                if os.path.isfile(file_path):
                    if self._should_include_file(file_path, include_patterns, exclude_patterns):
                        try:
                            file_info = self.file_type_registry.get_file_info(file_path)
                            files.append(file_info)
                        except (OSError, PermissionError):
                            # 忽略无法访问的文件
                            continue
        except PermissionError:
            print(f"无法访问目录: {directory}")

        return files

    def _scan_recursive(
        self,
        directory: str,
        include_patterns: Optional[List[str]],
        exclude_patterns: Optional[List[str]],
        max_depth: Optional[int],
        current_depth: int,
        scanned_count: int
    ) -> List[FileInfo]:
        """递归扫描目录"""
        files = []

        # 检查深度限制
        if max_depth is not None and current_depth > max_depth:
            return files

        try:
            entries = os.listdir(directory)
        except PermissionError:
            print(f"无法访问目录: {directory}")
            return files

        for entry in entries:
            file_path = os.path.join(directory, entry)

            try:
                if os.path.isfile(file_path):
                    if self._should_include_file(file_path, include_patterns, exclude_patterns):
                        try:
                            file_info = self.file_type_registry.get_file_info(file_path)
                            files.append(file_info)
                        except (OSError, PermissionError):
                            continue
                elif os.path.isdir(file_path):
                    # 递归扫描子目录
                    sub_files = self._scan_recursive(
                        file_path,
                        include_patterns,
                        exclude_patterns,
                        max_depth,
                        current_depth + 1,
                        scanned_count
                    )
                    files.extend(sub_files)
            except (OSError, PermissionError):
                # 忽略无法访问的文件/目录
                continue

        return files

    def _should_include_file(
        self,
        file_path: str,
        include_patterns: Optional[List[str]],
        exclude_patterns: Optional[List[str]]
    ) -> bool:
        """判断是否应该包含该文件"""
        filename = os.path.basename(file_path)

        # 检查排除模式
        if exclude_patterns:
            for pattern in exclude_patterns:
                if self._match_pattern(filename, pattern):
                    return False

        # 检查包含模式
        if include_patterns:
            for pattern in include_patterns:
                if self._match_pattern(filename, pattern):
                    return True
            return False

        # 默认包含所有支持的文件类型
        return self.file_type_registry.is_supported(file_path)

    def _match_pattern(self, filename: str, pattern: str) -> bool:
        """简单的模式匹配"""
        import fnmatch
        return fnmatch.fnmatch(filename.lower(), pattern.lower())

    def get_scan_statistics(self, files: List[FileInfo]) -> Dict[str, Any]:
        """
        获取扫描统计信息

        Args:
            files: 扫描到的文件列表

        Returns:
            Dict[str, Any]: 统计信息
        """
        if not files:
            return {
                "total_files": 0,
                "total_size": 0,
                "file_types": {},
                "size_distribution": {}
            }

        total_files = len(files)
        total_size = sum(f.size for f in files)

        # 按文件类型统计
        file_types = {}
        for file_info in files:
            file_type = file_info.file_type.value
            if file_type not in file_types:
                file_types[file_type] = 0
            file_types[file_type] += 1

        # 按文件大小分布
        size_distribution = {
            "small": 0,    # < 1MB
            "medium": 0,   # 1MB - 10MB
            "large": 0,    # > 10MB
            "huge": 0      # > 100MB
        }

        for file_info in files:
            size_mb = file_info.size / (1024 * 1024)
            if size_mb < 1:
                size_distribution["small"] += 1
            elif size_mb < 10:
                size_distribution["medium"] += 1
            elif size_mb < 100:
                size_distribution["large"] += 1
            else:
                size_distribution["huge"] += 1

        return {
            "total_files": total_files,
            "total_size": total_size,
            "total_size_mb": round(total_size / (1024 * 1024), 2),
            "file_types": file_types,
            "size_distribution": size_distribution,
            "average_file_size_mb": round(total_size / total_files / (1024 * 1024), 2) if total_files > 0 else 0
        }

    def find_duplicates(self, files: List[FileInfo]) -> Dict[str, List[FileInfo]]:
        """
        查找重复文件（基于文件名）

        Args:
            files: 文件信息列表

        Returns:
            Dict[str, List[FileInfo]]: 重复文件字典
        """
        duplicates = {}
        name_groups = {}

        # 按文件名分组
        for file_info in files:
            if file_info.name not in name_groups:
                name_groups[file_info.name] = []
            name_groups[file_info.name].append(file_info)

        # 找出重复的文件
        for name, group in name_groups.items():
            if len(group) > 1:
                duplicates[name] = group

        return duplicates

    def generate_scan_report(self, files: List[FileInfo]) -> str:
        """
        生成扫描报告

        Args:
            files: 扫描到的文件列表

        Returns:
            str: 格式化的扫描报告
        """
        stats = self.get_scan_statistics(files)
        duplicates = self.find_duplicates(files)

        report = f"""
=== 文档扫描报告 ===
扫描目录: {self.data_dir}

📊 基本统计:
- 文件总数: {stats['total_files']}
- 总大小: {stats['total_size_mb']} MB
- 平均文件大小: {stats['average_file_size_mb']} MB

📁 文件类型分布:
"""

        for file_type, count in sorted(stats['file_types'].items()):
            percentage = (count / stats['total_files']) * 100
            report += f"- {file_type}: {count} ({percentage:.1f}%)\n"

        report += f"""
📏 大小分布:
- 小文件 (<1MB): {stats['size_distribution']['small']}
- 中等文件 (1-10MB): {stats['size_distribution']['medium']}
- 大文件 (10-100MB): {stats['size_distribution']['large']}
- 超大文件 (>100MB): {stats['size_distribution']['huge']}
"""

        if duplicates:
            report += f"""
⚠️  重复文件:
发现 {len(duplicates)} 个文件名重复:
"""
            for name, dup_files in list(duplicates.items())[:5]:  # 只显示前5个
                report += f"- {name} ({len(dup_files)}个副本)\n"

        return report.strip()